/**
 * WhiMAIcpp - C++ interface for the Whiskey Media APIs.
 *  Copyright (C) 2010  Anders Bugge
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "list.h"

// STL includes
#ifdef WHIMAI_DEBUG
#include <iostream>
#endif

// VMA includes
#include "apikeys.h"

namespace WM
{

const std::string URL_APIKEY = "/?api_key=";
const std::string URL_LIMIT = "&limit=";
const std::string URL_OFFSET = "&offset=";
const std::string URL_FORMAT = "&format=json";

ListBase::ListBase( std::string name, std::string site, std::string key ) : Parser()
{
	type = name;
	URL_START = site;
	apikey = key;
	URL_EXTRA = "";
}

ListBase::ListBase( std::string name, std::string site, std::string key, unsigned int offset, unsigned int limit, bool* ok ) : Parser()
{
	type = name;
	URL_START = site;
	apikey = key;
	URL_EXTRA = "";
	update( offset, limit, ok );
}

ListBase::~ListBase()
{
}

void ListBase::update( unsigned int offset, unsigned int limit, bool* ok )
{
	// update request url
	std::stringstream ss;
	ss << URL_START << type << URL_APIKEY << apikey << URL_LIMIT << limit << URL_OFFSET << offset << URL_EXTRA << URL_FORMAT;
	url = ss.str();

	// get the data
	bool okay = parseData();
	if( ok )
		*ok = okay;
}

size_t ListBase::Size() const
{
	try
	{
		const json::Number& num = jObject->Find("number_of_page_results")->element;
		return (size_t)num.Value();
	}
	catch( const json::Exception& e)
	{
#ifdef WHIMAI_DEBUG
		std::cout << "JSON ERROR: " << e.what() << std::endl;
#endif
	}
	return 0;
}

size_t ListBase::TotalSize() const
{
	try
	{
		const json::Number& num = jObject->Find("number_of_total_results")->element;
		return (size_t)num.Value();
	}
	catch( const json::Exception& e)
	{
#ifdef WHIMAI_DEBUG
		std::cout << "JSON ERROR: " << e.what() << std::endl;
#endif
	}
	return 0;
}

double ListBase::asValue( unsigned int index, std::string item, bool* ok )
{
	bool okay = false;
	try
	{
		int pos = item.find(',');
		std::string item2 = "";
		if( pos != std::string::npos )
		{
			char buf[100] = {'\0'};
			item.copy( buf, item.size()-pos-1, pos+1);
			item2 += buf;
			char buf2[100] = {'\0'};
			item.copy( buf2, pos, 0);
			item = buf2;
		}

		const json::UnknownElement& uElm = getElement( index, item, &okay );
		if( ok )
			*ok = false;

		if( okay )
		{
			if( item2.empty() )
				return ((json::Number)uElm).Value();
			else
				return ((json::Number)(uElm[item2])).Value();
		}
	}
	catch( const json::Exception& e)
	{
#ifdef WHIMAI_DEBUG
		std::cout << "JSON ERROR: " << e.what() << std::endl;
#endif
	}
	return 0.0;
}

std::string ListBase::asString( unsigned int index, std::string item, bool* ok )
{
	bool okay = false;
	try
	{
		int pos = item.find(',');
		std::string item2 = "";
		if( pos != std::string::npos )
		{
			char buf[100] = {'\0'};
			item.copy( buf, item.size()-pos-1, pos+1);
			item2 += buf;
			char buf2[100] = {'\0'};
			item.copy( buf2, pos, 0);
			item = buf2;
		}

		const json::UnknownElement& uElm = getElement( index, item, &okay );
		if( ok )
			*ok = okay;

		if( okay )
		{
			if( item2.empty() )
				return ((json::String)uElm).Value();
			else
				return ((json::String)(uElm[item2])).Value();
		}
	}
	catch( const json::Exception& e)
	{
#ifdef WHIMAI_DEBUG
		std::cout << "JSON ERROR: " << e.what() << std::endl;
#endif
	}
	return "";
}

Array* ListBase::asArray( unsigned int index, std::string item, bool* ok )
{
	if( arrays.find(item) != arrays.end() )
		return arrays[item];

	bool okay = false;
	try
	{
		const json::UnknownElement& uElm = getElement( index, item, &okay );
		if( ok )
			*ok = okay;

		if( okay )
		{
			arrays[item] = new Array( ((const json::Array&)uElm) );
			return arrays[item];
		}
	}
	catch( const json::Exception& e)
	{
#ifdef WHIMAI_DEBUG
		std::cout << "JSON ERROR: " << e.what() << std::endl;
#endif
	}

	return NULL;
}

const json::UnknownElement& ListBase::getElement( unsigned int index, std::string fieldList, bool* ok )
{
	try
	{
		if( index < Size() )
		{
			const json::UnknownElement& uElm = jObject->Find("results")->element[index][fieldList];
			*ok = true;
			return uElm;
		}

		json::Exception e = json::Exception("Array index out of range");
		throw e;
	}
	catch( const json::Exception& e)
	{
#ifdef WHIMAI_DEBUG
		std::cout << "JSON ERROR: " << e.what() << std::endl;
#endif
		*ok = false;
	}

	const json::UnknownElement& uElm = json::UnknownElement();
	return uElm;
}

namespace GB
{

List::List( std::string name ) : ListBase( name, "http://api.giantbomb.com/", APIKEY )
{

}

List::List( std::string name, unsigned int offset, unsigned int limit, bool* ok ) : ListBase( name, "http://api.giantbomb.com/", APIKEY, offset, limit, ok )
{

}

}

namespace CV
{

List::List( std::string name ) : ListBase( name, "http://api.comicvine.com/", APIKEY )
{

}

List::List( std::string name, unsigned int offset, unsigned int limit, bool* ok ) : ListBase( name, "http://api.comicvine.com/", APIKEY, offset, limit, ok )
{

}

}

}
